#include "gamehack.h"

#include <iostream>
#include <boost/algorithm/string.hpp>
#include <boost/regex.hpp>

#include "console.hpp"
#include "gamebot.hpp"
#include "tcc_regex.hpp"
#include "mhook/mhook-lib/mhook.h"

#define GAME_CLIENT_NAME "Droiyan Online.exe"

template<typename R, typename T>
R Transform(T value)
{
	union
	{
		T src;
		R dst;
	}trans;
	trans.src = value;
	return trans.dst;
}

bool GameHack::Initialize(HINSTANCE dll_hanlde)
{
	if (NULL == dll_hanlde)
		return false;

	char mod_name[MAX_PATH];
	GetModuleFileNameA(GetModuleHandleA(NULL), mod_name, sizeof(mod_name) - 1);
	if (std::string(mod_name).find(GAME_CLIENT_NAME) == std::string::npos)
		return false;

	self_hadle_ = dll_hanlde;

	sConsole.Initialize();
	sConsole.Start(boost::bind(&GameHack::ProcessCmd, this, _1));

	InitScriptEngine();

	is_initialized_ = true;

	return true;
}
void GameHack::Finalize()
{
	if (!is_initialized_)
		return;
	
	tcc_delete(tcc_);
	
	sConsole.Stop();
}
bool GameHack::InitScriptEngine()
{
	tcc_ = tcc_new();
	tcc_add_include_path(tcc_, "./include/winapi");
	tcc_set_output_type(tcc_, TCC_OUTPUT_MEMORY);
	tcc_add_file(tcc_, "main_script.c");
	tcc_add_symbol(tcc_, "printf", &printf);
	tcc_add_symbol(tcc_, "install_hook", &install_hook);
	tcc_add_symbol(tcc_, "uninstall_hook", &uninstall_hook);

	if (tcc_relocate(tcc_, TCC_RELOCATE_AUTO) >= 0)
	{
		int (*prog_main)(int, const char*);
		prog_main = (int(*)(int, const char*))tcc_get_symbol(tcc_, "main");
		if (NULL != prog_main)
		{
			int ret = (*prog_main)(0, NULL);
		}
	}
	return true;
}
void GameHack::ProcessCmd(std::string& cmd)
{
	std::vector<std::string> cmd_list;
	boost::algorithm::split(cmd_list, cmd, boost::algorithm::is_any_of(" "));

	if(cmd_list.empty())
		return;

	if (cmd_list.size() == 2 && cmd_list[0] == "do")
	{
		TCCState* tcc = tcc_new();
		if (NULL == tcc)
			return;

		tcc_add_include_path(tcc, "./include/winapi");
		tcc_set_output_type(tcc, TCC_OUTPUT_MEMORY);
		tcc_add_file(tcc, cmd_list[1].c_str());
		tcc_add_symbol(tcc, "printf", &printf);

		tcc_add_symbol(tcc, "tcc_regex_new", &tcc_regex::tcc_regex_new);
		tcc_add_symbol(tcc, "tcc_regex_delete", &tcc_regex::tcc_regex_delete);
		tcc_add_symbol(tcc, "tcc_regex_search", Transform<void*>(&tcc_regex::tcc_regex_search));

		tcc_add_symbol(tcc, "tcc_match_new", &tcc_smatch::tcc_smatch_new);
		tcc_add_symbol(tcc, "tcc_match_delete", &tcc_smatch::tcc_smatch_delete);
		tcc_add_symbol(tcc, "tcc_get_match", Transform<void*>(&tcc_smatch::tcc_get_match));

		if (tcc_relocate(tcc, TCC_RELOCATE_AUTO) >= 0)
		{
			int (*prog_main)(int, const char*);
			prog_main = (int(*)(int, const char*))tcc_get_symbol(tcc, "main");
			if (NULL != prog_main)
			{
				int ret = (*prog_main)(0, NULL);
			}
		}
		tcc_delete(tcc);
	}
}